home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1991
/
02
/
nelson
/
bitio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-03
|
6KB
|
168 lines
/*
* Listing 4 -- bitio.c
*
* This routine contains a set of bit oriented i/o routines
* used for arithmetic data compression. The important fact to
* know about these is that the first bit is stored in the msb of
* the first byte of the output, like you might expect.
*
* Both input and output maintain a local buffer so that they only
* have to do block reads and writes. This is done in spite of the
* fact that C standard I/O does the same thing. If these
* routines are ever ported to assembly language the buffering
* will come in handy.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "coder.h"
#include "bitio.h"
#define BUFFER_SIZE 256
static char buffer[ BUFFER_SIZE + 2 ]; /* This is the i/o buffer */
static char *current_byte; /* Pointer to current byte */
static int output_mask; /* During output, this byte */
/* contains the mask that is */
/* applied to the output byte*/
/* if the output bit is a 1 */
static int input_bytes_left; /* During input, these three */
static int input_bits_left; /* variables keep track of my*/
static int past_eof; /* input state. The past_eof*/
/* byte comes about because */
/* of the fact that there is */
/* a possibility the decoder */
/* can legitimately ask for */
/* more bits even after the */
/* entire file has been */
/* sucked dry. */
/*
* This routine is called once to initialze the output bitstream.
* All it has to do is set up the current_byte pointer, clear out
* all the bits in my current output byte, and set the output mask
* so it will set the proper bit next time a bit is output.
*/
void initialize_output_bitstream()
{
current_byte = buffer;
*current_byte = 0;
output_mask = 0x80;
}
/*
* The output bit routine just has to set a bit in the current byte
* if requested to. After that, it updates the mask. If the mask
* shows that the current byte is filled up, it is time to go to the
* next character in the buffer. If the next character is past the
* end of the buffer, it is time to flush the buffer.
*/
void output_bit( FILE *stream, int bit )
{
if ( bit )
*current_byte |= output_mask;
output_mask >>= 1;
if ( output_mask == 0 )
{
output_mask = 0x80;
current_byte++;
if ( current_byte == ( buffer + BUFFER_SIZE ) )
{
fwrite( buffer, 1, BUFFER_SIZE, stream );
current_byte = buffer;
}
*current_byte = 0;
}
}
/*
* When the encoding is done, there will still be a lot of bits and
* bytes sitting in the buffer waiting to be sent out. This routine
* is called to clean things up at that point.
*/
void flush_output_bitstream( FILE *stream )
{
fwrite( buffer, 1, (size_t)( current_byte - buffer ) + 1, stream );
current_byte = buffer;
}
/*
* Bit oriented input is set up so that the next time the input_bit
* routine is called, it will trigger the read of a new block. That
* is why input_bits_left is set to 0.
*/
void initialize_input_bitstream()
{
input_bits_left = 0;
input_bytes_left = 1;
past_eof = 0;
}
/*
* This routine reads bits in from a file. The bits are all sitting
* in a buffer, and this code pulls them out, one at a time. When the
* buffer has been emptied, that triggers a new file read, and the
* pointers are reset. This routine is set up to allow for two dummy
* bytes to be read in after the end of file is reached. This is because
* we have to keep feeding bits into the pipeline to be decoded so that
* the old stuff that is 16 bits upstream can be pushed out.
*/
short int input_bit( FILE *stream )
{
if ( input_bits_left == 0 )
{
current_byte++;
input_bytes_left--;
input_bits_left = 8;
if ( input_bytes_left == 0 )
{
input_bytes_left = fread( buffer, 1, BUFFER_SIZE, stream );
if ( input_bytes_left == 0 )
{
if ( past_eof )
{
fprintf( stderr, "Bad input file\n" );
exit( -1 );
}
else
{
past_eof = 1;
input_bytes_left = 2;
}
}
current_byte = buffer;
}
}
input_bits_left--;
return ( ( *current_byte >> input_bits_left ) & 1 );
}
/*
* When monitoring compression ratios, we need to know how many
* bytes have been output so far. This routine takes care of telling
* how many bytes have been output, including pending bytes that
* haven't actually been written out.
*/
long bit_ftell_output( FILE *stream )
{
long total;
total = ftell( stream );
total += current_byte - buffer;
total += underflow_bits/8;
return( total );
}
/*
* When monitoring compression ratios, we need to know how many bits
* have been read in so far. This routine tells how many bytes have
* been read in, excluding bytes that are pending in the buffer.
*/
long bit_ftell_input( FILE *stream )
{
return( ftell( stream ) - input_bytes_left + 1 );
}